/**
 *  Copyright 2013 Nate Dierk
 *
 *  COMP 590 -- Fall 2013
 */

#ifndef GPixel_nd_DEFINED
#define GPixel_nd_DEFINED

#include "GContext.h"
#include "GPaint.h"
#include "GPixel.h"

#define GPIXEL_SCALE_FACTOR 255

///////////////////////////////////////////////////////////
 // GPixel Methods

 enum BlendType{
  SET,       // ignores and overwrites any existing values: dst = src
  SRC_OVER,  // source over blending: dst = src + (1 - src.fA)*dst
};

static inline unsigned GPixel_CompPreMul(float alpha, float c){
  return (unsigned) floorf(alpha * c * GPIXEL_SCALE_FACTOR + 0.5f);
}

// premul and pack into pixel
static inline GPixel GPixel_PackColor(const GColor& color){
  return GPixel_PackARGB( 
    GPixel_CompPreMul(    1.0f, color.fA), //alpha is special, doesn't pre-mul itself
    GPixel_CompPreMul(color.fA, color.fR), 
    GPixel_CompPreMul(color.fA, color.fG), 
    GPixel_CompPreMul(color.fA, color.fB)
    ); 
}

static inline unsigned divide255(unsigned component){
  int result = ((component * 257) + (257 << 7)) >> 16;
  GASSERT(result >= 0 && result <= 255);
  return result;
}

static inline void GPixel_Scale(GPixel* pix, unsigned factor){
  GASSERT(factor <= 255);

  uint32_t a, r, g, b;
  a = divide255(GPixel_GetA(*pix) * factor);
  r = divide255(GPixel_GetR(*pix) * factor);
  g = divide255(GPixel_GetG(*pix) * factor);
  b = divide255(GPixel_GetB(*pix) * factor);

  *pix = GPixel_PackARGB(a, r, g, b);
}

//may be unnecessary
static inline void GPixel_Add(GPixel* dst, const GPixel& src){
	uint32_t a, r, g, b;

	a = (GPixel_GetA(*dst) + GPixel_GetA(src)) & 0xFF;
	r = (GPixel_GetR(*dst) + GPixel_GetR(src)) & 0xFF;
	g = (GPixel_GetG(*dst) + GPixel_GetG(src)) & 0xFF;
	b = (GPixel_GetB(*dst) + GPixel_GetB(src)) & 0xFF;

	*dst = GPixel_PackARGB(a, r, g, b);
};

#endif